/*
    Matali Physics Demo
    Copyright (c) 2011 KOMIRES Sp. z o. o.
 */
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Komires.MataliPhysics;

namespace MataliPhysicsDemo
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class CursorDraw1
    {
        Demo demo;
        PhysicsScene scene;

        string defaultName;

        BasicEffect effect;
        VertexPositionColor[] cursorVertices;

        Matrix transform;
        Matrix projection;
        Matrix view;
        Matrix world;

        Vector3 ambient;
        Vector3 diffuse;
        Vector3 emission;
        Vector3 specular;

        Vector3 lightDirection;
        Vector3 lightDiffuse;
        Vector3 lightSpecular;

        Matrix matrixIdentity;

        Vector3 startPosition;
        Vector3 endPosition;

        public CursorDraw1(Demo demo)
        {
            this.demo = demo;

            defaultName = "Default";

            cursorVertices = new VertexPositionColor[2];

            matrixIdentity = Matrix.Identity;
        }

        public void Initialize(PhysicsScene scene)
        {
            this.scene = scene;

            effect = new BasicEffect(demo.GraphicsDevice);
        }

        public void SetControllers()
        {
            PhysicsObject objectBase = null;

            objectBase = scene.Factory.PhysicsObjectManager.Find("Cursor A");
            if (objectBase != null)
                objectBase.UserControllers.DrawMethods += new DrawMethod(Draw);

            objectBase = scene.Factory.PhysicsObjectManager.Find("Cursor B");
            if (objectBase != null)
                objectBase.UserControllers.DrawMethods += new DrawMethod(Draw);

            objectBase = scene.Factory.PhysicsObjectManager.Find("Cursor");
            if (objectBase != null)
                objectBase.UserControllers.DrawMethods += new DrawMethod(DrawLine);
        }

        public void Draw(DrawMethodArgs args)
        {
            PhysicsScene scene = demo.Engine.Factory.PhysicsSceneManager.Get(args.OwnerSceneIndex);
            PhysicsObject objectBase = scene.Factory.PhysicsObjectManager.Get(args.OwnerIndex);

            if (!objectBase.EnableDrawing) return;

            PhysicsObject physicsObjectWithActiveCamera = scene.GetPhysicsObjectsWithActiveCamera(0);

            if (physicsObjectWithActiveCamera == null) return;

            PhysicsCamera activeCamera = physicsObjectWithActiveCamera.Camera;

            if (activeCamera == null) return;

            float time = args.Time;

            activeCamera.View.GetViewMatrix(ref view);
            activeCamera.Projection.GetProjectionMatrix(ref projection);
            objectBase.MainWorldTransform.GetTransformMatrix(ref world);

            if (objectBase.UserTagStr != null)
            {
                demo.GraphicsDevice.DepthStencilState = DepthStencilState.None;

                DemoMesh mesh = demo.Meshes[objectBase.UserTagStr];
                PhysicsLight sceneLight = scene.Light;
                sceneLight.GetDirection(ref lightDirection);
                sceneLight.GetDiffuse(ref lightDiffuse);
                sceneLight.GetSpecular(ref lightSpecular);

                Matrix worldBone;

                if (mesh.Model != null)
                {
                    objectBase.Material.GetAmbient(ref ambient);
                    objectBase.Material.GetDiffuse(ref diffuse);
                    objectBase.Material.GetEmission(ref emission);
                    objectBase.Material.GetSpecular(ref specular);

                    demo.GraphicsDevice.RasterizerState = RasterizerState.CullClockwise;

                    Model model = mesh.Model;

                    foreach (ModelMesh modelMesh in model.Meshes)
                    {
                        foreach (BasicEffect effect in modelMesh.Effects)
                        {
                            transform = model.Bones[modelMesh.ParentBone.Index].Parent.Transform;
                            Matrix.Multiply(ref transform, ref world, out worldBone);

                            effect.View = view;
                            effect.World = worldBone;
                            effect.Projection = projection;

                            if (objectBase.Material.UserTagStr != null)
                            {
                                effect.TextureEnabled = true;
                                effect.Texture = demo.Textures[objectBase.Material.UserTagStr];
                            }
                            else
                            {
                                effect.TextureEnabled = true;
                                effect.Texture = demo.Textures[defaultName];
                            }

                            effect.AmbientLightColor = ambient;
                            effect.DiffuseColor = diffuse;
                            effect.SpecularColor = specular;
                            effect.EmissiveColor = emission;
                            effect.SpecularPower = objectBase.Material.SpecularPower;
                            effect.Alpha = objectBase.Material.TransparencyFactor;

                            effect.DirectionalLight0.Direction = lightDirection;
                            effect.DirectionalLight0.DiffuseColor = lightDiffuse;
                            effect.DirectionalLight0.SpecularColor = lightSpecular;
                            effect.DirectionalLight0.Enabled = true;
                            effect.LightingEnabled = true;
                            effect.PreferPerPixelLighting = true;
                        }

                        modelMesh.Draw();
                    }
                }
                else
                {
                    mesh.Effect.View = view;
                    mesh.Effect.World = world;
                    mesh.Effect.Projection = projection;

                    mesh.Effect.DirectionalLight0.Direction = lightDirection;
                    mesh.Effect.DirectionalLight0.DiffuseColor = lightDiffuse;
                    mesh.Effect.DirectionalLight0.SpecularColor = lightSpecular;
                    mesh.Effect.DirectionalLight0.Enabled = true;
                    mesh.Effect.LightingEnabled = true;
                    mesh.Effect.PreferPerPixelLighting = true;

                    mesh.Draw(objectBase.Material, false);
                }

                demo.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            }
        }

        public void DrawLine(DrawMethodArgs args)
        {
            PhysicsScene scene = demo.Engine.Factory.PhysicsSceneManager.Get(args.OwnerSceneIndex);
            PhysicsObject objectBase = scene.Factory.PhysicsObjectManager.Get(args.OwnerIndex);

            if (!objectBase.EnableDrawing) return;

            PhysicsObject physicsObjectWithActiveCamera = scene.GetPhysicsObjectsWithActiveCamera(0);

            if (physicsObjectWithActiveCamera == null) return;

            PhysicsCamera activeCamera = physicsObjectWithActiveCamera.Camera;

            if (activeCamera == null) return;

            demo.GraphicsDevice.DepthStencilState = DepthStencilState.None;

            float time = args.Time;

            CursorController cursorController = physicsObjectWithActiveCamera.InternalControllers.CursorController;

            if ((cursorController != null) && cursorController.IsDragging)
            {
                activeCamera.View.GetViewMatrix(ref view);
                activeCamera.Projection.GetProjectionMatrix(ref projection);
                world = matrixIdentity;

                cursorController.GetAnchor1(ref startPosition);
                cursorController.GetAnchor2(ref endPosition);

                Color diffuseColor1 = Color.White;
                Color diffuseColor2 = Color.MediumSpringGreen;

                effect.View = view;
                effect.World = world;
                effect.Projection = projection;

                effect.VertexColorEnabled = true;
                effect.TextureEnabled = false;
                effect.LightingEnabled = false;

                cursorVertices[0].Position.X = startPosition.X;
                cursorVertices[0].Position.Y = startPosition.Y;
                cursorVertices[0].Position.Z = startPosition.Z;
                cursorVertices[0].Color = diffuseColor2;

                cursorVertices[1].Position.X = endPosition.X;
                cursorVertices[1].Position.Y = endPosition.Y;
                cursorVertices[1].Position.Z = endPosition.Z;
                cursorVertices[1].Color = diffuseColor1;

                effect.Techniques[0].Passes[0].Apply();

                demo.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, cursorVertices, 0, 1);
            }

            demo.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
        }
    }
}
